#include "bsp_can.h"
#include "systick.h"
#include "bsp.h"
#include <string.h>

    //CAN0和CAN1共用28个滤波器，CAN0可全部占用28个,CAN1不用，也可以CAN1全部占用，CAN0不用,需要注意的是，三路CAN各自至少需要配置一个滤波器，才能正常接收
#define CAN1_FILTER_START_BANK 14

static osTimeCost_T p1[2];

dv_CAN_TypeDef dv_CAN;

    // CAN_CHG
    // Tx->PB6 -> CAN1_TX(remap)
    // Rx->PB5 -> CAN1_Rx(remap)

    // CAN_SUB
    // Tx->PA12 -> CAN0_TX(alternate 2)
    // Rx->PA11 -> CAN0_RX(alternate 2) 

    // CAN_MAIN
    // Tx->PA10 -> CAN2_TX(alternate 1)
    // Rx->PA9  -> CAN2_RX(alternate 1)

static void SUB_NVIC_Config(void)
{
    nvic_irq_enable(CAN0_RX0_IRQn,2,2);
}
static void CHG_NVIC_Config(void)
{
    nvic_irq_enable(CAN1_RX0_IRQn,2,2);
}
static void MAIN_NVIC_Config(void)
{
    nvic_irq_enable(CAN2_RX0_IRQn,2,2);
}

static void can_gpio_config(CAN_CH_DEF can_ch)
{
    switch (can_ch)
    {
    case EM_CAN_0: 
    {
          // enable CAN clock
        rcu_periph_clock_enable(RCU_CAN0);
        rcu_periph_clock_enable(RCU_GPIOA);
	    rcu_periph_clock_enable(RCU_AF);

          // configure CANX GPIO
        gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
        gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
        break;
    }
    case EM_CAN_1: 
    {
          // enable CAN clock
        rcu_periph_clock_enable(RCU_CAN1);
        rcu_periph_clock_enable(RCU_GPIOB);
        rcu_periph_clock_enable(RCU_AF);

        rcu_periph_clock_enable(RCU_CAN0);
        can1_filter_start_bank(CAN1_FILTER_START_BANK);

          // configure CANX GPIO
        gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
        gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);

        gpio_pin_remap_config(GPIO_CAN1_REMAP, ENABLE);
        break;
    }
    case EM_CAN_2: 
    {
          // enable CAN clock
        rcu_periph_clock_enable(RCU_CAN2);
        rcu_periph_clock_enable(RCU_GPIOA);
        rcu_periph_clock_enable(RCU_AF);

          // configure CANX GPIO
        gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
        gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

        gpio_afio_port_config(AFIO_PA9_CAN2_CFG, ENABLE);
        gpio_afio_port_config(AFIO_PA10_CAN2_CFG, ENABLE);

        break;
    }

    default: 
        break;
    }
}

static void can_class_config(CAN_CH_DEF can_ch)
{
    can_parameter_struct can_parameter;
    uint32_t canx;

    switch (can_ch)
    {
    case EM_CAN_0: 
        canx = CAN0;
        break;
    case EM_CAN_1: 
        canx = CAN1;
        break;
    case EM_CAN_2: 
        canx = CAN2;
        break;
    default: 
        break;
    }
    can_deinit(canx);
    can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
    can_parameter.time_triggered        = DISABLE;
    can_parameter.auto_bus_off_recovery = ENABLE;
    can_parameter.auto_wake_up          = ENABLE;
    can_parameter.auto_retrans          = DISABLE;
    can_parameter.rec_fifo_overwrite    = DISABLE;
    can_parameter.trans_fifo_order      = ENABLE;
    can_parameter.working_mode          = CAN_NORMAL_MODE;
#if BPS_CAN0_1M_2M
      /* baudrate 1Mbps, sample piont at 80% */
    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
    can_parameter.time_segment_1    = CAN_BT_BS1_7TQ;
    can_parameter.time_segment_2    = CAN_BT_BS2_2TQ;
    can_parameter.prescaler         = 9U;
#else
      /* baudrate 250kbps, sample piont at 80% */
    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
    can_parameter.time_segment_1    = CAN_BT_BS1_15TQ;
    can_parameter.time_segment_2    = CAN_BT_BS2_4TQ;
    can_parameter.prescaler         = 18U;              // 90M/(1+15+4)/18 = 250 Kbps
#endif
      /* initialize CAN */
    can_init(canx, &can_parameter);
}

static void can_enFD_config(CAN_CH_DEF can_ch)
{
    can_fdframe_struct can_fd_parameter;
    can_fd_tdc_struct can_fd_tdc_parameter;

    uint32_t canx;

    switch (can_ch)
    {
    case EM_CAN_0: 
        canx = CAN0;
        break;
    case EM_CAN_1: 
        canx = CAN1;
        break;
    case EM_CAN_2: 
        canx = CAN2;
        break;
    default: 
        break;
    }

    can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter);
    can_fd_parameter.fd_frame             = ENABLE;
    can_fd_parameter.excp_event_detect    = ENABLE;
    can_fd_parameter.delay_compensation   = ENABLE;
    can_fd_tdc_parameter.tdc_filter       = 0x04U;
    can_fd_tdc_parameter.tdc_mode         = CAN_TDCMOD_CALC_AND_OFFSET;
    can_fd_tdc_parameter.tdc_offset       = 0x04U;
    can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter;
    can_fd_parameter.iso_bosch            = CAN_FDMOD_ISO;
    can_fd_parameter.esi_mode             = CAN_ESIMOD_HARDWARE;
#if BPS_CAN0_1M_2M
      /* baudrate 2Mbps, sample piont at 80% */
    can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ;
    can_fd_parameter.data_time_segment_1    = CAN_BT_BS1_3TQ;
    can_fd_parameter.data_time_segment_2    = CAN_BT_BS2_1TQ;
    can_fd_parameter.data_prescaler         = 9U;
#else
      /* baudrate 250kbps, sample piont at 80% */
    can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ;
    can_fd_parameter.data_time_segment_1    = CAN_BT_BS1_15TQ;
    can_fd_parameter.data_time_segment_2    = CAN_BT_BS2_4TQ;
    can_fd_parameter.data_prescaler         = 18U;              // 90M/(1+15+4)/18 = 250 Kbps
#endif
      /* initialize CAN-FD */
    can_fd_init(canx, &can_fd_parameter);
}

static void can_maskfilter_config(CAN_CH_DEF can_ch)
{
    uint32_t canx;
    can_filter_parameter_struct can_filter;

    switch (can_ch)
    {
    case EM_CAN_0: 
    {
        canx                     = CAN0;
        can_filter.filter_number = 0;
        break;
    }
    case EM_CAN_1: 
    {
        canx                     = CAN1;
        can_filter.filter_number = CAN1_FILTER_START_BANK;
        break;
    }
    case EM_CAN_2: 
    {
        canx                     = CAN2;
        can_filter.filter_number = 0;
        break;
    }
    default: 
        break;
    }

    can_filter.filter_mode        = CAN_FILTERMODE_MASK;
    can_filter.filter_bits        = CAN_FILTERBITS_32BIT;
    can_filter.filter_fifo_number = CAN_FIFO0;
    can_filter.filter_enable      = ENABLE;
    can_filter.filter_list_high   = 0x0000;
    can_filter.filter_list_low    = 0x0000;
    can_filter.filter_mask_high   = 0x0000;
    can_filter.filter_mask_low    = 0x0000;
    can_filter_init(canx, &can_filter);
}

static void can_listerfilter_config(CAN_CH_DEF can_ch)
{
    can_filter_parameter_struct can_filter;

      // 数组大小不能小于4
    uint32_t can0_idlist[4] = {RX_MES1_ID, 0, 0, 0};
    uint32_t can1_idlist[4] = {0x01};
    uint32_t can2_idlist[4] = {0x01};
    uint32_t canx;
    uint32_t *canx_idlist;
    uint8_t idlistCnt = 0;

    switch (can_ch)
    {
    case EM_CAN_0: 
    {
        canx                     = CAN0;
        can_filter.filter_number = 0;
        canx_idlist              = can0_idlist;
        idlistCnt                = sizeof(can0_idlist) / sizeof(uint32_t) / 2;
        idlistCnt                = (sizeof(can0_idlist) / sizeof(uint32_t) % 2) ? (idlistCnt + 1) : (idlistCnt);
        break;
    }
    case EM_CAN_1: 
    {
        canx                     = CAN1;
        can_filter.filter_number = CAN1_FILTER_START_BANK;
        canx_idlist              = can1_idlist;
        idlistCnt                = sizeof(can1_idlist) / sizeof(uint32_t) / 2;
        idlistCnt                = (sizeof(can1_idlist) / sizeof(uint32_t) % 2) ? (idlistCnt + 1) : (idlistCnt);
        break;
    }
    case EM_CAN_2: 
    {
        canx                     = CAN2;
        can_filter.filter_number = 0;
        canx_idlist              = can2_idlist;
        idlistCnt                = sizeof(can2_idlist) / sizeof(uint32_t) / 2;
        idlistCnt                = (sizeof(can2_idlist) / sizeof(uint32_t) % 2) ? (idlistCnt + 1) : (idlistCnt);
        break;
    }
    default: 
        break;
    }

    can_filter.filter_mode        = CAN_FILTERMODE_LIST;
    can_filter.filter_bits        = CAN_FILTERBITS_32BIT;
    can_filter.filter_fifo_number = CAN_FIFO0;
    can_filter.filter_enable      = ENABLE;
    for (uint8_t i = 0; i < idlistCnt; i++)
    {
        can_filter.filter_list_high = (uint16_t)((canx_idlist[i * 2] << 3) >> 16) & 0xFFFF;
        can_filter.filter_list_low  = (uint16_t)((canx_idlist[i * 2] << 3)) & 0xFFFE | CAN_FF_EXTENDED | CAN_FT_DATA;
        can_filter.filter_mask_high = (uint16_t)((canx_idlist[i * 2 + 1] << 3) >> 16) & 0xFFFF;
        can_filter.filter_mask_low  = (uint16_t)((canx_idlist[i * 2 + 1] << 3)) & 0xFFFE | CAN_FF_EXTENDED | CAN_FT_DATA;
        can_filter_init(canx, &can_filter);
        can_filter.filter_number += 1;
    }
}

static void can_txrx_init(CAN_CH_DEF can_ch, uint8_t fden, uint8_t brs)
{
    can_trasnmit_message_struct *Txpara;
    can_receive_message_struct *Rxpara;
    switch (can_ch)
    {
    case EM_CAN_0: 
    {
        Txpara = &dv_CAN.sub_transmit_message;
        Rxpara = &dv_CAN.sub_receive_message;
        break;
    }
    case EM_CAN_1: 
    {
        Txpara = &dv_CAN.chg_transmit_message;
        Rxpara = &dv_CAN.chg_receive_message;
        break;
    }
    case EM_CAN_2: 
    {
        Txpara = &dv_CAN.main_transmit_message;
        Rxpara = &dv_CAN.main_receive_message;
        break;
    }
    default: 
        break;
    }
    can_struct_para_init(CAN_TX_MESSAGE_STRUCT, Txpara);
    Txpara->tx_sfid = 0x00;
    Txpara->tx_efid = 0x00;
    Txpara->tx_ft   = CAN_FT_DATA;
    Txpara->tx_ff   = CAN_FF_EXTENDED;
    Txpara->tx_dlen = 8;
    Txpara->fd_flag = fden;
      /* close the switch of FD data bit rate */
    Txpara->fd_brs = brs;
    Txpara->fd_esi = 0;

      /* initialize receive message */
    can_struct_para_init(CAN_RX_MESSAGE_STRUCT, Rxpara);
}

static void bsp_can_init(CAN_CH_DEF can_ch, bool fd_en)
{
    uint8_t enfd = 0;

    enfd = (fd_en == true) ? (1) : (0);

    switch (can_ch)
    {
    case EM_CAN_0: 
          // SUB_CAN FD
        can_gpio_config(EM_CAN_0);
        can_class_config(EM_CAN_0);
        if (fd_en)
        {
            can_enFD_config(EM_CAN_0);
        }
          // can_listerfilter_config(EM_CAN_0);
        can_maskfilter_config(EM_CAN_0);
        can_txrx_init(EM_CAN_0, enfd, 0);
          /* configure CAN0 NVIC */
        SUB_NVIC_Config();
          /* enable CAN0 receive FIFO0 not empty interrupt */
        can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
        break;
    case EM_CAN_1: 
          // CHG_CAN
        can_gpio_config(EM_CAN_1);
        can_class_config(EM_CAN_1);
        if (fd_en)
        {
            can_enFD_config(EM_CAN_1);
        }
          // can_listerfilter_config(EM_CAN_1);
        can_maskfilter_config(EM_CAN_1);
        can_txrx_init(EM_CAN_1, enfd, 0);
          /* configure CAN1 NVIC */
        CHG_NVIC_Config();
          /* enable CAN1 receive FIFO0 not empty interrupt */
        can_interrupt_enable(CAN1, CAN_INTEN_RFNEIE0);
        break;
    case EM_CAN_2: 
          // MAIN_CAN
        can_gpio_config(EM_CAN_2);
        can_class_config(EM_CAN_2);
        if (fd_en)
        {
            can_enFD_config(EM_CAN_2);
        }
          // can_listerfilter_config(EM_CAN_2);
        can_maskfilter_config(EM_CAN_2);
        can_txrx_init(EM_CAN_2, enfd, 0);
          /* configure CAN2 NVIC */
        MAIN_NVIC_Config();
          /* enable CAN2 receive FIFO0 not empty interrupt */
        can_interrupt_enable(CAN2, CAN_INTEN_RFNEIE0);
        break;
    default: 
        break;
    }	
}

static void bsp_can_sendFrame(CAN_CH_DEF can_ch, uint32_t id, uint8_t *data, uint8_t len)
{
    static                  uint32_t timeout = 0;
    can_transmit_state_enum transtate        = CAN_TRANSMIT_FAILED;
    uint8_t transmail;
    uint32_t canx;
    can_trasnmit_message_struct *Txpara;

    switch (can_ch)
    {
    case EM_CAN_0: 
    {
        canx   = CAN0;
        Txpara = &dv_CAN.sub_transmit_message;
        break;
    }
    case EM_CAN_1: 
    {
        canx   = CAN1;
        Txpara = &dv_CAN.chg_transmit_message;
        break;
    }
    case EM_CAN_2: 
    {
        canx   = CAN2;
        Txpara = &dv_CAN.main_transmit_message;
        break;
    }
    default: 
        break;
    }

    Txpara->tx_efid = id;

    if (len <= 8)
        len = len;
    else if (len <= 12)
        len = 12;
    else if (len <= 16)
        len = 16;
    else if (len <= 20)
        len = 20;
    else if (len <= 24)
        len = 24;
    else if (len <= 32)
        len = 32;
    else if (len <= 48)
        len = 48;
    else
    len             = 64;
    Txpara->tx_dlen = len;
    for (uint8_t i = 0; i < Txpara->tx_dlen; ++i)
    {
        Txpara->tx_data[i] = data[i];
    }
    transmail = can_message_transmit(canx, Txpara);
    if (transmail == CAN_NOMAILBOX)
    {
        return;
    }
    else
    {
        timeout = 0;
        while (transtate != CAN_TRANSMIT_OK)
        {
            transtate = can_transmit_states(canx, transmail);
            delay_1ms(1);
            timeout++;
            if (timeout >= 10)
                break;
        }
    }
}

static void communication_loop(void)
{
    can_receive_message_struct *rxframe;
    if (dv_CAN.sub_receive_flag)
    {
        dv_CAN.sub_receive_flag = false;
        rxframe                 = &dv_CAN.sub_receive_message;
        bsp_can_sendFrame(EM_CAN_0, rxframe->rx_efid, rxframe->rx_data, rxframe->rx_dlen);
    }

    if (dv_CAN.chg_receive_flag)
    {
        dv_CAN.chg_receive_flag = false;
        rxframe                 = &dv_CAN.chg_receive_message;
        bsp_can_sendFrame(EM_CAN_1, rxframe->rx_efid, rxframe->rx_data, rxframe->rx_dlen);
    }

    if (dv_CAN.main_receive_flag)
    {
        dv_CAN.main_receive_flag = false;
        rxframe                  = &dv_CAN.main_receive_message;
        bsp_can_sendFrame(EM_CAN_2, rxframe->rx_efid, rxframe->rx_data, rxframe->rx_dlen);
    }
}

void init_bsp_can(void)
{
    dv_CAN.finit               = bsp_can_init;
    dv_CAN.fwrite_data         = bsp_can_sendFrame;
    dv_CAN.fcommunication_loop = communication_loop;
}

void CAN0_RX0_IRQHandler(void)
{
    uint8_t mesNum;
    mesNum = can_receive_message_length_get(CAN0,CAN_FIFO0);
    for (uint8_t i = 0; i < mesNum; i++)
    {
        can_message_receive(CAN0, CAN_FIFO0, &dv_CAN.sub_receive_message);
    }   	
    dv_CAN.sub_receive_flag = SET;
}

void CAN1_RX0_IRQHandler(void)
{
   uint8_t mesNum;
    mesNum = can_receive_message_length_get(CAN1,CAN_FIFO0);
    for (uint8_t i = 0; i < mesNum; i++)
    {
        can_message_receive(CAN1, CAN_FIFO0, &dv_CAN.chg_receive_message);
    }   	
    dv_CAN.chg_receive_flag = SET;
}

void CAN2_RX0_IRQHandler(void)
{    
    uint8_t mesNum;
    mesNum = can_receive_message_length_get(CAN2,CAN_FIFO0);
    for (uint8_t i = 0; i < mesNum; i++)
    {
        can_message_receive(CAN2, CAN_FIFO0, &dv_CAN.main_receive_message);
        if(dv_CAN.main_receive_message.rx_efid == RX_MES1_ID)
        {
            memcpy(&dv_CAN.main_receive_mes1_message,&dv_CAN.main_receive_message,sizeof(can_receive_message_struct));
            dv_CAN.main_receive_mes1_flag = SET;
        }
    }   	
    dv_CAN.main_receive_flag = SET;
}
